use std::{rc::Rc, cell::RefCell, sync::Arc};

use crate::{instructions::base::{Instruction, BytecodeReader}, rtda::{Frame, heap, OperandStack, Object}};

// 第一个操作数是个uint16索引，通过这个索引可以从运行时常量池中找到一个类符号引用，解析这个引用就可以得到多维数组类。
// 第二个操作数是个uint8整数，表示数组维度。
// 还需要从操作数栈中弹出n个整数，分别代表每一个维度的数组长度。
#[derive(Debug, Default)]
pub struct MULTI_ANEW_ARRAY {
    index: usize,
    dimensions: u8, // 数组维度
}

impl Instruction for MULTI_ANEW_ARRAY {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.index = reader.read_u16() as usize;
        self.dimensions = reader.read_u8();
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let cp = frame.borrow().get_method().get_class().get_constant_pool().unwrap();
        let class_ref = cp.get_constant(self.index).unwrap().class_ref();
        // 数组类
        let arr_class = class_ref.lock().unwrap().resolved_class();

        let stack = frame.borrow().get_operand_stack();
        let counts = pop_and_check_counts(stack.clone(), self.dimensions as usize);
        let arr = new_multi_dimensional_array(&counts, arr_class);
        stack.borrow_mut().push_ref(Some(arr));
    }
}

// 从操作数栈中弹出n个整数，分别代表每一个维度的数组长度。
fn pop_and_check_counts(stack: Rc<RefCell<OperandStack>>, dimensions: usize) -> Vec<i32> {
    let mut counts = vec![0; dimensions];
    for i in (0..dimensions).rev() {
        counts[i] = stack.borrow_mut().pop_int();
        if counts[i] < 0 {
            panic!("java.lang.NegativeAraySizeException")
        }
    }
    counts
}

// 创建多维数组,由最外围数组开始。
fn new_multi_dimensional_array(counts: &[i32], arr_class: Arc<heap::Class>) -> *mut Object {
    let count = counts[0] as usize;
    let mut arr = heap::Class::new_array(arr_class.clone(), count);
    if counts.len() > 1 {
        let refs = arr.array().refs();
        for i in 0..refs.len() {
            refs[i] = Some(new_multi_dimensional_array(&counts[1..], arr_class.component_class()));
        }
    }
    Box::into_raw(Box::new(arr))
}